home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d2 / nansi286.arc / NANSI_P.ASM < prev    next >
Assembly Source File  |  1987-07-19  |  10KB  |  304 lines

  1. ;----- nansi_p.asm --------------------------------------------------------
  2. ; A state machine implementation of the mechanics of ANSI terminal control
  3. ; string parsing.
  4. ; (C) 1986 Daniel Kegel, Pasadena, CA
  5. ; May be distributed for educational and personal use only
  6. ;
  7. ; Entered with a jump to f_escape when driver finds an escape, or
  8. ; to f_in_escape when the last string written to this device ended in the
  9. ; middle of an escape sequence.
  10. ;
  11. ; Exits by jumping to f_ANSI_exit when an escape sequence ends, or
  12. ; to f_not_ANSI when a bad escape sequence is found, or (after saving state)
  13. ; to f_loopdone when the write ends in the middle of an escape sequence.
  14. ;
  15. ; Parameters are stored as bytes in param_buffer.  If a parameter is
  16. ; omitted, it is stored as zero.  Each character in a keyboard reassignment
  17. ; command counts as one parameter.
  18. ;
  19. ; When a complete escape sequence has been parsed, the address of the
  20. ; ANSI routine to call is found in ansi_fn_table.
  21. ;
  22. ; Register usage during parsing:
  23. ;  DS:SI points to the incoming string.
  24. ;  CX holds the length remaining in the incoming string.
  25. ;  ES:DI points to the current location on the memory-mapped screen.
  26. ;  DX is number of characters remaining on the current screen line.
  27. ;  BX points to the current paramter byte being assembled from the incoming
  28. ;  string.  (Stored in cur_parm_ptr between device driver calls, if needed.)
  29. ;
  30. ; The registers are set as follows before calling the ANSI subroutine:
  31. ;  AX = max(1, value of first parameter)
  32. ;  CX = number of paramters
  33. ;  SI = offset of second parameter from CS
  34. ;  DS = CS
  35. ;  ES:DI points to the current location on the memory-mapped screen.
  36. ;  DX is number of characters remaining on the current screen line.
  37. ; The subroutine is free to trash AX, BX, CX, SI, and DS.
  38. ; It must preserve ES, and can alter DX and DI if it wants to move the
  39. ; cursor.
  40. ;
  41. ; Revision history:
  42. ; 7 July 85: created by DRK
  43. ;------------------------------------------------------------------------
  44.  
  45.     ; From nansi.asm
  46.     extrn    f_not_ANSI:near        ; exit: abort bad ANSI cmd
  47.     extrn    f_ANSI_exit:near    ; exit: good cmd done
  48.     extrn    f_loopdone:near        ; exit: ran out of chars. State saved.
  49.     extrn    escvector:word        ; saved state: where to jump
  50.     extrn    cur_parm_ptr:word    ; saved state: where to put next param
  51.     extrn    string_term:byte    ; saved state: what ends string
  52.     extrn    cur_x:byte, max_x:byte    ; 0 <= cur_x <= max_x
  53.     extrn    cur_attrib:byte        ; current color/attribute
  54.     extrn    xlate_tab_ptr:word
  55.  
  56.     ; from nansi_f.asm
  57.     extrn    ansi_fn_table:word    ; ANSI subroutine table
  58.  
  59.     ; Used in nansi.asm
  60.     public    f_escape        ; entry: found an escape
  61.     public    f_in_escape        ; entry: restore state, keep parsing
  62.  
  63.     ; Used in nansi_i.asm and nansi_f.asm
  64.     public    param_buffer, param_end, redef_end
  65.  
  66.  
  67. code    segment byte public 'CODE'
  68.     assume    cs:code
  69.  
  70. ; More saved state
  71. in_num        db    ?    ; true if between a digit and a semi in parse
  72.  
  73. param_buffer    dw    3000h    ; address of first byte free for new params
  74. param_end    dw    3030h    ; address of end of free area
  75. redef_end    dw    3030h    ; address of end of redefinition area
  76.         ; These initialized values are only for debugging
  77.  
  78. ;----- next_is -------------------------------------------------------
  79. ; Next_is is used to advance to the next state.  If there are characters
  80. ; left in the input string, we jump immediately to the new state;
  81. ; otherwise, we shut down the recognizer, and wait for the next call
  82. ; to the device driver.
  83. next_is macro    statename
  84.     loop    statename
  85.     mov    ax, offset statename
  86.     jmp    sleep
  87.     endm
  88.  
  89. ;----- sleep --------------------------------------------------------
  90. ; Remember bx and next state, then jump to device driver exit routine.
  91. ; Device driver will re-enter at f_in_escape upon next invocation
  92. ; because escvector is nonzero; parsing will then be resumed.
  93. sleep:    mov    cs:cur_parm_ptr, bx
  94.     mov    cs:escvector, ax
  95.     jmp    f_loopdone
  96.  
  97. ;----- f_in_escape ---------------------------------------------------
  98. ; Main loop noticed that escvector was not zero.
  99. ; Recall value of BX saved when sleep was jumped to, and jump into parser.
  100. f_in_escape:
  101.     mov    bx, cs:cur_parm_ptr
  102.     jmp    word ptr cs:escvector
  103.  
  104. fbr_syntax_error_gate:        ; jumped to from inside f_bracket
  105.     jmp    syntax_error
  106.  
  107. ;----- f_escape ------------------------------------------------------
  108. ; We found an escape.  Next character should be a left bracket.
  109. f_escape:
  110.     next_is f_bracket
  111.  
  112. ;----- f_bracket -----------------------------------------------------
  113. ; Last char was an escape.  This one should be a [; if not, print it.
  114. ; Next char should begin a parameter string.
  115. f_bracket:
  116.     lodsb
  117.     cmp    al, '['
  118.     jnz    fbr_syntax_error_gate
  119.     ; Set up for getting a parameter string.
  120.     mov    bx, cs:param_buffer
  121.     mov    byte ptr cs:[bx], 0
  122.     mov    cs:in_num, 0
  123.     next_is f_get_args
  124.  
  125. ;----- f_get_args ---------------------------------------------------
  126. ; Last char was a [.  If the current char is a '=' or a '?', eat it.
  127. ; In any case, proceed to f_get_param.
  128. ; This is only here to strip off the strange chars that follow [ in
  129. ; the SET/RESET MODE escape sequence.
  130. f_get_args:
  131.     lodsb
  132.     cmp    al, '='
  133.     jz    fga_ignore
  134.     cmp    al, '?'
  135.     jz    fga_ignore
  136.         dec    si        ; let f_get_param fetch al again
  137.         jmp    short f_get_param
  138. fga_ignore:
  139.     next_is f_get_param
  140.  
  141. ;----- f_get_param ---------------------------------------------------
  142. ; Last char was one of the four characters "]?=;".
  143. ; We are getting the first digit of a parameter, a quoted string,
  144. ; a ;, or a command.
  145. f_get_param:
  146.     lodsb
  147.     cmp    al, '0'
  148.     jb    fgp_may_quote
  149.     cmp    al, '9'
  150.     ja    fgp_may_quote
  151.         ; It's the first digit.  Initialize current parameter with it.
  152.         sub    al, '0'
  153.         mov    byte ptr cs:[bx], al
  154.         mov    cs:in_num, 1    ; set flag for sensing at cmd exec
  155.         next_is f_in_param
  156. fgp_may_quote:
  157.     cmp    al, '"'
  158.     jz    fgp_isquote
  159.     cmp    al, "'"
  160.     jnz    fgp_semi_or_cmd        ; jump to code shared with f_in_param
  161. fgp_isquote:
  162.     mov    cs:string_term, al    ; save it for end of string
  163.     next_is f_get_string        ; and read string into param_buffer
  164.  
  165. ;----- f_get_string -------------------------------------
  166. ; Last character was a quote or a string element.
  167. ; Get characters until ending quote found.
  168. f_get_string:
  169.     lodsb
  170.     cmp    al, cs:string_term
  171.     jz    fgs_init_next_param
  172.     mov    byte ptr cs:[bx], al
  173.     cmp    bx, cs:param_end
  174.     adc    bx, 0            ; if bx<param_end bx++;
  175.     next_is f_get_string
  176. ; Ending quote was found.
  177. fgs_init_next_param:
  178.     mov    byte ptr cs:[bx], 0    ; initialize new parameter
  179.     ; | Eat following semicolon, if any.
  180.     next_is f_eat_semi
  181.  
  182. ;----- f_eat_semi -------------------------------------
  183. ; Last character was an ending quote.
  184. ; If this char is a semi, eat it; else unget it.
  185. ; Next state is always f_get_param.
  186. f_eat_semi:
  187.     lodsb
  188.     cmp    al, ';'
  189.     jz    fes_eaten
  190.         inc    cx
  191.         dec    si
  192. fes_eaten:
  193.     next_is f_get_param
  194.  
  195. ;----- syntax_error ---------------------------------------
  196. ; A character was rejected by the state machine.  Exit to
  197. ; main loop, and print offending character.  Let main loop
  198. ; decrement CX (length of input string).
  199. syntax_error:
  200.     mov    cs:escvector, 0
  201.     mov    ah, cs:cur_attrib
  202.     mov    bx, cs:xlate_tab_ptr
  203.     jmp    f_not_ANSI    ; exit, print offending char
  204.  
  205. ;------ f_in_param -------------------------------------
  206. ; Last character was a digit.
  207. ; Looking for more digits, a semicolon, or a command character.
  208. f_in_param:
  209.     lodsb
  210.     cmp    al, '0'
  211.     jb    fgp_semi_or_cmd
  212.     cmp    al, '9'
  213.     ja    fgp_semi_or_cmd
  214.         ; It's another digit.  Add into current parameter.
  215.         sub    al, '0'
  216.         xchg    byte ptr cs:[bx], al
  217.         push    dx
  218.         mov    dl, 10
  219.         mul    dl
  220.         pop    dx
  221.         add    byte ptr cs:[bx], al
  222.         next_is f_in_param
  223.     ; Code common to states get_param and in_param.
  224.     ; Accepts a semicolon or a command letter.
  225. fgp_semi_or_cmd:
  226.     cmp    al, ';'
  227.     jnz    fgp_not_semi
  228.         cmp    bx, cs:param_end    ; prepare for next param-
  229.         adc    bx, 0            ; if bp<param_end bp++;
  230.         ; Set new param to zero, enter state f_get_param.
  231.         mov    cs:in_num, 0        ; no longer inside number
  232.         jmp    fgs_init_next_param    ; spaghetti code attack!
  233. fgp_not_semi:
  234.     ; It must be a command letter.
  235.     cmp    al, '@'
  236.     jb    syntax_error
  237.     cmp    al, 'z'
  238.     ja    syntax_error
  239.     cmp    al, 'Z'
  240.     jbe    fgp_is_cmd
  241.     cmp    al, 'a'
  242.     jb    syntax_error
  243.         ; It's a lower-case command letter.
  244.         ; Remove hole between Z and a to save space in table.
  245.         sub    al, 'a'-'['
  246. fgp_is_cmd:
  247.     ; It's a command letter.  Save registers, convert letter
  248.     ; into address of routine, set up new register usage, call routine.
  249.     push    si            ; These three registers hold info
  250.     push    cx            ; having to do with the input string,
  251.     push    ds            ; which has no interest at all to the
  252.                     ; control routine.
  253.  
  254.     push    cs
  255.     pop    ds            ; ds is now cs
  256.  
  257.     sub    al, '@'            ; first command is @: insert chars
  258.     cbw
  259.     add    ax, ax
  260.     add    ax, offset ansi_fn_table
  261.     ; ax is now pointer to command routine address in table
  262.  
  263.     mov    cx, bx
  264.     mov    si, param_buffer    ; si is now pointer to parameters
  265.     sub    cx, si            ;
  266.     test    in_num, 1
  267.     jz    fip_out_num
  268.         inc    cx
  269. fip_out_num:                ; cx is now # of parameters
  270.  
  271.     xchg    ax, bx            ; save pointer to routine in bx
  272.  
  273.     ; Calculate cur_x from DX.
  274.     mov    al, max_x
  275.     inc    ax
  276.     sub    al, dl
  277.     mov    cur_x, al
  278.  
  279.     ; Get first parameter into AX; if defaulted, set it to 1.
  280.     mov    ah, 0
  281.     lodsb
  282.     or    al, al
  283.     jnz    fgp_callem
  284.         inc    ax
  285. fgp_callem:
  286.     ; Finally, call the command subroutine.
  287.     call    word ptr [bx]
  288.  
  289.     pop    ds
  290.     pop    cx
  291.     pop    si
  292.  
  293.     mov    ah, cs:cur_attrib    ; Prepare for STOSW.
  294.     mov    bx, cs:xlate_tab_ptr    ; Prepare for translation.
  295.     mov    cs:escvector, 0        ; No longer parsing escape sequence.
  296.     ; Set flags for reentry at loopnz
  297.     or    dx, dx            ; "Any columns left on line?"
  298.     ; Re-enter at bottom of main loop.
  299.     jmp    f_ansi_exit
  300.  
  301.  
  302. code    ends
  303.     end                ; of nansi_p.asm
  304.